package com.example.chamberlainserver.Service.impl;

import com.example.chamberlainserver.Entry.User;
import com.example.chamberlainserver.Entry.UserLoginLog;
import com.example.chamberlainserver.Service.AuthService;
import com.example.chamberlainserver.Service.SmsService;
import com.example.chamberlainserver.Service.UserLogService;
import com.example.chamberlainserver.Service.UserService;
import com.example.chamberlainserver.Service.UserRoleService;
import com.example.chamberlainserver.Service.RoleService;
import com.example.chamberlainserver.Entry.Role;
import com.example.chamberlainserver.Vo.Request.User.LoginVo;

import java.util.List;
import com.example.chamberlainserver.Vo.Request.User.PhoneLoginVo;
import com.example.chamberlainserver.Vo.Request.User.RegisterVo;
import com.example.chamberlainserver.Vo.Request.User.SmsCodeRequestVo;
import com.example.chamberlainserver.Vo.Response.ApiResponse;
import com.example.chamberlainserver.Vo.Response.JwtResponse;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.UUID;

import com.example.chamberlainserver.event.AuthenticationEvent;
import com.example.chamberlainserver.event.AuthenticationResultEvent;
import com.example.chamberlainserver.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SmsService smsService;
    private CompletableFuture<AuthenticationResultEvent> authResultFuture;

    @Autowired
    private UserLogService userLogService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ApplicationEventPublisher eventPublisher; // 添加事件发布者

    @Autowired
    private PasswordEncoder passwordEncoder; // 添加密码编码器
    
    @Autowired
    private UserRoleService userRoleService;
    
    @Autowired
    private RoleService roleService;

    @Override
    public JwtResponse login(LoginVo loginRequest) {
        // 验证用户名和密码不为空
        if (loginRequest.getUsername().isEmpty() || loginRequest.getPassword().isEmpty()) {
            throw new IllegalArgumentException("用户名或密码不能为空");
        }

        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
        String ipAddress = getIpAddress(request);
        String userAgent = request != null ? request.getHeader("User-Agent") : "";

        try {
            // 创建新的CompletableFuture来等待认证结果
            authResultFuture = new CompletableFuture<>();

            // 发布认证事件
            eventPublisher.publishEvent(new AuthenticationEvent(
                    this, loginRequest.getUsername(), loginRequest.getPassword()));

            // 等待认证结果，最多等待5秒
            AuthenticationResultEvent resultEvent = authResultFuture.get(5, TimeUnit.SECONDS);

            // 获取用户信息（无论成功失败都记录日志）
            User user = null;
            try {
                user = userMapper.getUserByStuNo(loginRequest.getUsername());
            } catch (Exception e) {
                // 用户不存在，忽略异常
            }

            // 记录登录日志（只有用户存在时才记录）
            if (user != null) {
                int userId = user.getId();
                int status = resultEvent.isSuccess() ? 1 : 0; // 成功为1，失败为0
                String message = resultEvent.isSuccess() ? "登录成功" : resultEvent.getErrorMessage();
                userLogService.recordUserLogin(userId, ipAddress, status, message, userAgent);
            }

            if (!resultEvent.isSuccess()) {
                throw new RuntimeException("登录失败: " + resultEvent.getErrorMessage());
            }

            // 返回JWT响应
            return new JwtResponse(resultEvent.getToken(), user.getStuNo(), getPrimaryUserRole(user.getId()));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            // 不记录登录失败日志，避免外键约束问题
            throw new RuntimeException("登录处理超时或被中断", e);
        } catch (Exception e) {
            // 不记录登录失败日志，避免外键约束问题
            throw new RuntimeException("登录失败: " + e.getMessage(), e);
        }
    }

    @EventListener
    public void handleAuthenticationResult(AuthenticationResultEvent event) {
        // 如果authResultFuture不为null且未完成，则完成它
        if (authResultFuture != null && !authResultFuture.isDone()) {
            authResultFuture.complete(event);
        }
    }

    /**
     * 获取请求IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }

        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    @Override
    public String register(RegisterVo registerRequest) {
        // 验证用户名和密码不为空
        if (registerRequest.getNickName().isEmpty() || registerRequest.getPassword().isEmpty()) {
            throw new IllegalArgumentException("用户名或密码不能为空");
        }

        // 检查用户是否已存在
        User existingUser = userMapper.findByPhone(registerRequest.getPhone()); // 假设通过手机号检查用户是否存在
        if (existingUser != null) {
            throw new IllegalArgumentException("用户已存在");
        }

        User newUser = new User();
        newUser.setNickName(registerRequest.getNickName());
        newUser.setName(registerRequest.getName());
        newUser.setClassName(registerRequest.getClassName());
        newUser.setStuNo(registerRequest.getStuNo()); // 添加学号设置
        newUser.setPhone(registerRequest.getPhone());
        newUser.setEmail(registerRequest.getEmail());
        // 角色将通过用户角色关联表管理，这里不再设置role字段
        newUser.setGender(registerRequest.getGender());
        newUser.setStatus("1"); // 默认为在校状态
        // 直接保存前端传递的已加密密码，不再进行二次加密
        newUser.setPassword(registerRequest.getPassword()); // 注册时加密密码

        // 保存用户
        userService.addUser(newUser);
        
        // 为新用户分配默认角色
        String defaultRole = registerRequest.getRole() != null ? registerRequest.getRole() : "STUDENT";
        Role role = roleService.getRoleByCode(defaultRole);
        if (role != null) {
            userRoleService.assignRolesToUser(newUser.getId(), java.util.Arrays.asList(role.getId()));
        }

        return "注册成功";
    }
    
    /**
     * 获取用户的主要角色
     */
    private String getPrimaryUserRole(Integer userId) {
        List<Role> roles = userRoleService.getRolesByUserId(userId);
        if (roles != null && !roles.isEmpty()) {
            // 返回第一个角色的角色代码
            return roles.get(0).getRoleCode();
        }
        // 如果没有角色，返回默认角色
        return "STUDENT";
    }

    @Override
    public String sendSmsCode(SmsCodeRequestVo smsCodeRequest) {
        String phoneNumber = smsCodeRequest.getPhone();
        // 生成6位随机验证码
        String smsCode = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        // 将验证码存储到 Redis，有效期5分钟
        stringRedisTemplate.opsForValue().set("sms:" + phoneNumber, smsCode, 5, TimeUnit.MINUTES);
        // 调用发送短信的类
        String code = "{\"code\":\"" + smsCode + "\"}";
        smsService.sendSms("GameBack", "SMS_463140324", phoneNumber, code); // 假设额外参数为模板ID等
        return "短信验证码已发送";
    }

    @Override
    public JwtResponse loginByPhone(PhoneLoginVo phoneLoginRequest) {
        String phoneNumber = phoneLoginRequest.getPhone();
        String smsCode = phoneLoginRequest.getSmsCode();

        // 从 Redis 获取验证码
        String storedSmsCode = stringRedisTemplate.opsForValue().get("sms:" + phoneNumber);

        if (storedSmsCode == null || !storedSmsCode.equals(smsCode)) {
            throw new IllegalArgumentException("验证码错误或已过期");
        }

        // 验证成功后，删除 Redis 中的验证码
        stringRedisTemplate.delete("sms:" + phoneNumber);

        // 查找用户或创建新用户
        User user = Optional.ofNullable(userMapper.findByPhone(phoneNumber)).orElseGet(() -> {
            User newUser = new User();
            newUser.setPhone(phoneNumber);
            newUser.setNickName("用户" + phoneNumber); // 简单生成用户名
            newUser.setPassword(passwordEncoder.encode(UUID.randomUUID().toString())); // 随机生成密码
            userMapper.insertUser(newUser);
            return newUser;
        });

        // 创建新的CompletableFuture来等待认证结果
        authResultFuture = new CompletableFuture<>();

        // 发布认证事件
        eventPublisher.publishEvent(new AuthenticationEvent(
                this, user.getStuNo(), user.getPassword()));

        try {
            // 等待认证结果，最多等待5秒
            AuthenticationResultEvent resultEvent = authResultFuture.get(5, TimeUnit.SECONDS);
            if (!resultEvent.isSuccess()) {
                throw new RuntimeException("登录失败: " + resultEvent.getErrorMessage());
            }
            return new JwtResponse(resultEvent.getToken(), user.getStuNo(), getPrimaryUserRole(user.getId()));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException("登录处理超时或被中断", e);
        }
    }
}
